/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.logiclander.adhocracy.jira.cli;

import com.logiclander.adhocracy.cli.CommandLineParserFactory;
import org.apache.commons.cli2.Argument;
import org.apache.commons.cli2.Group;
import org.apache.commons.cli2.Option;
import org.apache.commons.cli2.builder.ArgumentBuilder;
import org.apache.commons.cli2.builder.CommandBuilder;
import org.apache.commons.cli2.builder.DefaultOptionBuilder;
import org.apache.commons.cli2.builder.GroupBuilder;
import org.apache.commons.cli2.builder.SwitchBuilder;
import org.apache.commons.cli2.commandline.Parser;
import org.apache.commons.cli2.option.Command;
import org.apache.commons.cli2.option.Switch;
import org.apache.commons.cli2.util.HelpFormatter;


/**
 *
 * @author tim
 */
public class JiraCommandLineParserFactory implements CommandLineParserFactory {
    static final int TGL_STATUSCLOSED_ID = 400;
//    static final String TGL_STATUSCLOSED_NICKNAME = "";
    static final String TGL_STATUSCLOSED_FULLNAME = "statusClosed";
    static final String TGL_STATUSCLOSED_DESCRIPTION = "(optional) toggle view of issues with 'closed' status (default = disabled)";
    static final Switch TGL_STATUSCLOSED = statusClosed();
    
    static final int TGL_STATUSRESOLVED_ID = 401;
//    static final String TGL_STATUSRESOLVED_NICKNAME = "";
    static final String TGL_STATUSRESOLVED_FULLNAME = "statusResolved";
    static final String TGL_STATUSRESOLVED_DESCRIPTION = "(optional) toggle view of issues with 'resolved' status (default = enabled)";
    static final Switch TGL_STATUSRESOLVED = statusResolved();
    
    static final int TGL_TYPESUBTASK_ID = 402;
//    static final String TGL_TYPESUBTASK_NICKNAME = "";
    static final String TGL_TYPESUBTASK_FULLNAME = "typeSubtask";
    static final String TGL_TYPESUBTASK_DESCRIPTION = "(optional) toggle view of 'subtask' issues (default = disabled)";
    static final Switch TGL_TYPESUBTASK = typeSubtask();
    
    static final int TGL_CUSTOMRANK_ID = 403;
//    static final String TGL_CUSTOMRANK_NICKNAME = "";
    static final String TGL_CUSTOMRANK_FULLNAME = "customRank";
    static final String TGL_CUSTOMRANK_DESCRIPTION = "(optional) toggle sensitivity to processing custom field: 'rank' (default = disabled)";
    static final Switch TGL_CUSTOMRANK = customRank();
    
    static final int TGL_WATCHING_ID = 404;
//    static final String TGL_WATCHING_NICKNAME = "";
    static final String TGL_WATCHING_FULLNAME = "watching";
    static final String TGL_WATCHING_DESCRIPTION = "(optional) toggle filter on issues the authenticated user is 'watching' (default = disabled)";
    static final Switch TGL_WATCHING = watching();
    
    static final int ARG_PROJECTKEY_ID = 300;
    static final String ARG_PROJECTKEY_NICKNAME = "pky";
    static final String ARG_PROJECTKEY_FULLNAME = "projectKey";
    static final String ARG_PROJECTKEY_DESCRIPTION = "(required) specify project key to seed request";
    static final Argument ARG_PROJECTKEY = projectKey();
    
    static final int ARG_ISSUEKEY_ID = 301;
    static final String ARG_ISSUEKEY_NICKNAME = "iky";
    static final String ARG_ISSUEKEY_FULLNAME = "issueKey";
    static final String ARG_ISSUEKEY_DESCRIPTION = "(required) specify issue key to seed request";
    static final Argument ARG_ISSUEKEY = issueKey();

    static final int OPT_JIRAHELP_ID = 200;
    static final String OPT_JIRAHELP_NICKNAME = "h";
    static final String OPT_JIRAHELP_FULLNAME = "help";
    static final String OPT_JIRAHELP_DESCRIPTION = "(optional) get jira command line help";
    static final Option OPT_JIRAHELP = jiraHelp();

    static final int OPT_SPRINGCONTEXT_ID = 201;
    static final String OPT_SPRINGCONTEXT_NICKNAME = "scf";
    static final String OPT_SPRINGCONTEXT_FULLNAME = "springContextFilename";
    static final String OPT_SPRINGCONTEXT_DESCRIPTION = "(optional) specify alternate spring context configuration file to use";
    static final Option OPT_SPRINGCONTEXT = springContextFilename();

    static final int OPT_FILTERWATCHER_ID = 202;
    static final String OPT_FILTERWATCHER_NICKNAME = "fw";
    static final String OPT_FILTERWATCHER_FULLNAME = "filterWatcher";
    static final String OPT_FILTERWATCHER_DESCRIPTION = "(optional) specify netid to use in watcher filter";
    static final Option OPT_FILTERWATCHER = filterWatcher();

    static final int CMD_SHOWISSUE_ID = 100;
    static final String CMD_SHOWISSUE_NICKNAME = "si";
    static final String CMD_SHOWISSUE_FULLNAME = "showIssue";
    static final String CMD_SHOWISSUE_DESCRIPTION = "show issue summary for specified jira issue key";
    static final Command CMD_SHOWISSUE = showIssue();
    
    static final int CMD_SHOWPROJECT_ID = 101;
    static final String CMD_SHOWPROJECT_NICKNAME = "sp";
    static final String CMD_SHOWPROJECT_FULLNAME = "showProject";
    static final String CMD_SHOWPROJECT_DESCRIPTION = "show project summary for specified jira project key";
    static final Command CMD_SHOWPROJECT = showProject();
    
    static final int CMD_LISTISSUES_ID = 102;
    static final String CMD_LISTISSUES_NICKNAME = "li";
    static final String CMD_LISTISSUES_FULLNAME = "listIssues";
    static final String CMD_LISTISSUES_DESCRIPTION = "show list of issues for specified jira project key";
    static final Command CMD_LISTISSUES = listIssues();
    
    static final int CMD_LISTPROJECTS_ID = 103;
    static final String CMD_LISTPROJECTS_NICKNAME = "lp";
    static final String CMD_LISTPROJECTS_FULLNAME = "listProjects";
    static final String CMD_LISTPROJECTS_DESCRIPTION = "show list of projects available to authenticated user";
    static final Command CMD_LISTPROJECTS = listProjects();
    
    public Parser getParser() {
        Parser p = new Parser();
        Group options = getGroup();
        p.setGroup(options);
        p.setHelpFormatter(getHelpFormatter(options));
        p.setHelpOption(OPT_JIRAHELP);
        return p;
    }
    
    private Group getGroup() {
        GroupBuilder gb = new GroupBuilder();
        return gb.withDescription("jira commands:")
                 .withOption(CMD_SHOWISSUE)
                 .withOption(CMD_LISTISSUES)
                 .withOption(CMD_SHOWPROJECT)
                 .withOption(CMD_LISTPROJECTS)
                 .withOption(OPT_SPRINGCONTEXT)
                 .withOption(OPT_JIRAHELP)
                 .withMinimum(1)
                 .withMaximum(2)
                 .create();
    }
    
    private HelpFormatter getHelpFormatter(Group options) {
        HelpFormatter hf = new HelpFormatter();
        hf.setGroup(options);
        hf.setShellCommand(JiraCLI.class.getSimpleName());
        hf.setHeader("jira commandline i/o");
        return hf;
    }

    private static Command showIssue() {
        GroupBuilder gb = new GroupBuilder();
        Group g = gb.withOption(ARG_ISSUEKEY)
                    .create();
        CommandBuilder cb = new CommandBuilder();
        return cb.withId(CMD_SHOWISSUE_ID)
                 .withName(CMD_SHOWISSUE_NICKNAME)
                 .withChildren(g)
                 .withDescription(CMD_SHOWISSUE_DESCRIPTION)
                 .create();
    }
    
    private static Command listIssues() {
        GroupBuilder gb = new GroupBuilder();
        Group g = gb.withOption(ARG_PROJECTKEY)
                    .withOption(TGL_STATUSCLOSED)
                    .withOption(TGL_STATUSRESOLVED)
                    .withOption(TGL_TYPESUBTASK)
                    .withOption(TGL_CUSTOMRANK)
                    .withOption(TGL_WATCHING)
                    .withOption(OPT_FILTERWATCHER)
                    .create();
        CommandBuilder cb = new CommandBuilder();
        return cb.withId(CMD_LISTISSUES_ID)
                 .withName(CMD_LISTISSUES_NICKNAME)
                 .withChildren(g)
                 .withDescription(CMD_LISTISSUES_DESCRIPTION)
                 .create();
    }
    
    private static Command showProject() {
        GroupBuilder gb = new GroupBuilder();
        Group g = gb.withOption(ARG_PROJECTKEY)
                    .create();
        CommandBuilder cb = new CommandBuilder();
        return cb.withId(CMD_SHOWPROJECT_ID)
                 .withName(CMD_SHOWPROJECT_NICKNAME)
                 .withChildren(g)
                 .withDescription(CMD_SHOWPROJECT_DESCRIPTION)
                 .create();
    }
    
    private static Command listProjects() {
        CommandBuilder cb = new CommandBuilder();
        return cb.withId(CMD_LISTPROJECTS_ID)
                 .withName(CMD_LISTPROJECTS_NICKNAME)
                 .withDescription(CMD_LISTPROJECTS_DESCRIPTION)
                 .create();
    }
    
    private static Option springContextFilename() {
        ArgumentBuilder ab = new ArgumentBuilder();
        Argument a = ab.withName("SPRING_CONTEXT_FILENAME")
                       .withMinimum(1)
                       .withMaximum(1)
                       .withDescription("alternate spring context filename")
                       .create();
        DefaultOptionBuilder dob = new DefaultOptionBuilder();
        return dob.withId(OPT_SPRINGCONTEXT_ID)
                  .withShortName(OPT_SPRINGCONTEXT_NICKNAME)
                  .withLongName(OPT_SPRINGCONTEXT_FULLNAME)
                  .withDescription(OPT_SPRINGCONTEXT_DESCRIPTION)
                  .withArgument(a)
                  .create();
    }
    
    private static Option filterWatcher() {
        ArgumentBuilder ab = new ArgumentBuilder();
        Argument a = ab.withName("WATCHER_USERNAME")
                       .withMinimum(1)
                       .withMaximum(1)
                       .withDescription("(optional) netid to filter on watchers")
                       .create();
        DefaultOptionBuilder dob = new DefaultOptionBuilder();
        return dob.withId(OPT_FILTERWATCHER_ID)
                  .withShortName(OPT_FILTERWATCHER_NICKNAME)
                  .withLongName(OPT_FILTERWATCHER_FULLNAME)
                  .withDescription(OPT_FILTERWATCHER_DESCRIPTION)
                  .withArgument(a)
                  .create();
    }
    
    private static Option jiraHelp() {
        DefaultOptionBuilder dob = new DefaultOptionBuilder();
        return dob.withId(OPT_JIRAHELP_ID)
                  .withShortName(OPT_JIRAHELP_NICKNAME)
                  .withLongName(OPT_JIRAHELP_FULLNAME)
                  .withDescription(OPT_JIRAHELP_DESCRIPTION)
                  .create();
    }
    
    private static Switch statusClosed() {
        SwitchBuilder sb = new SwitchBuilder();
        return sb.withId(TGL_STATUSCLOSED_ID)
                 .withName(TGL_STATUSCLOSED_FULLNAME)
                 .withDescription(TGL_STATUSCLOSED_DESCRIPTION)
                 .withRequired(false)
                 .withSwitchDefault(Boolean.FALSE)
                 .create();
    }
    
    private static Switch statusResolved() {
        SwitchBuilder sb = new SwitchBuilder();
        return sb.withId(TGL_STATUSRESOLVED_ID)
                 .withName(TGL_STATUSRESOLVED_FULLNAME)
                 .withDescription(TGL_STATUSRESOLVED_DESCRIPTION)
                 .withRequired(false)
                 .withSwitchDefault(Boolean.TRUE)
                 .create();
    }
    
    private static Switch typeSubtask() {
        SwitchBuilder sb = new SwitchBuilder();
        return sb.withId(TGL_TYPESUBTASK_ID)
                 .withName(TGL_TYPESUBTASK_FULLNAME)
                 .withDescription(TGL_TYPESUBTASK_DESCRIPTION)
                 .withRequired(false)
                 .withSwitchDefault(Boolean.FALSE)
                 .create();
    }
    
    private static Switch customRank() {
        SwitchBuilder sb = new SwitchBuilder();
        return sb.withId(TGL_CUSTOMRANK_ID)
                 .withName(TGL_CUSTOMRANK_FULLNAME)
                 .withDescription(TGL_CUSTOMRANK_DESCRIPTION)
                 .withRequired(false)
                 .withSwitchDefault(Boolean.FALSE)
                 .create();
    }
    
    private static Switch watching() {
        SwitchBuilder sb = new SwitchBuilder();
        return sb.withId(TGL_WATCHING_ID)
                 .withName(TGL_WATCHING_FULLNAME)
                 .withDescription(TGL_WATCHING_DESCRIPTION)
                 .withRequired(false)
                 .withSwitchDefault(Boolean.FALSE)
                 .create();
    }
    
    private static Argument projectKey() {
        ArgumentBuilder ab = new ArgumentBuilder();
        return ab.withId(ARG_PROJECTKEY_ID)
                 .withName(ARG_PROJECTKEY_NICKNAME)
                 .withMinimum(0)
                 .withMaximum(1)
                 .withDescription(ARG_PROJECTKEY_DESCRIPTION)
                 .create();
//                 .withValidator(specific to project key)
    }
    
    private static Argument issueKey() {
        ArgumentBuilder ab = new ArgumentBuilder();
        return ab.withId(ARG_ISSUEKEY_ID)
                 .withName(ARG_ISSUEKEY_NICKNAME)
                 .withMinimum(1)
                 .withMaximum(1)
                 .withDescription(ARG_ISSUEKEY_DESCRIPTION)
                 .create();
//                 .withValidator(specific to issue key)
    }
    
}
